﻿using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace Tetris {
    // 格
    class Grid {
        public bool mUsed;  // 使用则为 true，否则为 false
    }

    // 带颜色的格
    class ColorGrid: Grid {
        public Color mColor;    // 颜色
    }

    // 方块
    abstract class Block {
        // 矩形
        private struct RECT {
            public int l;   // 左边界坐标
            public int t;   // 上边界坐标
            public int r;   // 右边界坐标
            public int b;   // 下边界坐标
            
            /**
             * 构造方法。
             * @param left      左边界坐标
             * @param top       上边界坐标
             * @param right     右边界坐标
             * @param bottom    下边界坐标
             */
            public RECT(int left, int top, int right, int bottom) {
                l = left;
                t = top;
                r = right;
                b = bottom;
            }

            /**
             * 构造方法。
             * @param rect  矩形
             */
            public RECT(Rectangle rect) {
                l = rect.Left;
                t = rect.Top;
                r = rect.Right;
                b = rect.Bottom;
            }
        }

        // 形状
        protected enum Shape {
            ONE,    // 形状1
            TWO,    // 形状2
            THREE,  // 形状3
            FOUR    // 形状4
        }
        
        // 导入画矩形边框的 API 函数
        [DllImport("user32", EntryPoint = "DrawEdge")]
        private static extern int DrawEdgeWin32(int hdc, ref RECT qrc, int edge, int grfFlags);
                
        private const int BF_RECT = 15;     // DrawEdge 函数的第四个参数
        private const int EDGE_RAISED = 5;  // DrawEdge 函数的第三个参数
        protected Grid[,] mBlocks;          // 方块数据
        protected Brush mBrush;             // 画刷
        protected Color mColor;             // 颜色
        protected Graphics mDrawer;         // 绘图者
        private Control mGameBoard;         // 游戏区域
        protected int mLine;                // 当前所在列(左)
        protected int mRow;                 // 当前所在行(上)
        protected Shape mShape = Shape.ONE; // 形状

        /**
         * 构造方法。
         */
        public Block() {
            mBlocks = new Grid[Const.BLOCK_GRID_COUNT_V, Const.BLOCK_GRID_COUNT_H];
            for (int i = 0; i < Const.BLOCK_GRID_COUNT_V; i++) {
                for (int j = 0; j < Const.BLOCK_GRID_COUNT_H; j++) {
                    mBlocks[i, j] = new Grid();
                }
            }

            byte[] rgb = new byte[3];
            Random random = new Random();
            random.NextBytes(rgb);
            mColor = Color.FromArgb(rgb[0], rgb[1], rgb[2]);
            mLine = 3;
            mRow = -1;
        }

        /**
         * 绘制自身。
         */
        public void Draw() {
            for (int i = 0; i < Const.BLOCK_GRID_COUNT_H; i++) {
                for (int j = 0; j < Const.BLOCK_GRID_COUNT_V; j++) {
                    if (!mBlocks[i, j].mUsed) {
                        continue;
                    }

                    int left = Const.GRID_SIZE * (mLine + j);
                    int top =  Const.GRID_SIZE * (mRow + i);
                    Rectangle rect = new Rectangle(left, top, Const.GRID_SIZE, Const.GRID_SIZE);
                    mDrawer.FillRectangle(new SolidBrush(mColor), rect);
                    Block.DrawEdge(mDrawer, rect);
                }
            }

            mGameBoard.Invalidate();
        }
                
        /*
         * 画矩形的边框，使矩形具有立体效果。
         * @param drawer    绘图者
         * @param rectangle 矩形
         */
        public static void DrawEdge(Graphics drawer, Rectangle rectangle) {
            int hdc = drawer.GetHdc().ToInt32();
            RECT rect = new RECT(rectangle);
            DrawEdgeWin32(hdc, ref rect, EDGE_RAISED, BF_RECT);
            drawer.ReleaseHdc();
        }

        /**
         * 进入游戏区域。
         * @param gameBoard 游戏区域
         * @param drawer    绘图者
         * @param brush     画刷
         */
        public void EnterGameboard(Control gameBoard, Graphics drawer, Brush brush) {
            mGameBoard = gameBoard;
            mDrawer = drawer;
            mBrush = brush;
            this.Draw();
        }

        /**
         * 进入预览区域。
         * @param drawer    绘图者
         */
        public virtual void EnterPreview(Graphics drawer) {
            int x = (Const.PREVIEW_WIDTH - Const.GRID_SIZE * 3) / 2;
            int y = Const.PREVIEW_HEIGHT / 2 - Const.GRID_SIZE * 2;

            // 遍历所有格，跳过无效的，画有效的
            for (int i = 0; i < Const.BLOCK_GRID_COUNT_H; i++) {
                for (int j = 0; j < Const.BLOCK_GRID_COUNT_V; j++) {
                    if (!mBlocks[i, j].mUsed) {
                        continue;
                    }

                    Rectangle rect = new Rectangle(x + Const.GRID_SIZE * j,
                        y + Const.GRID_SIZE * i, Const.GRID_SIZE, Const.GRID_SIZE);
                    drawer.FillRectangle(new SolidBrush(mColor), rect);
                    Block.DrawEdge(drawer, rect);
                }
            }
        }

        /**
         * 擦除。
         */
        protected abstract void Erase();
        
        /**
         * 擦除矩形。 
         * @param rect  矩形
         */
        protected void EraseRect(Rectangle rect) {
            mDrawer.FillRectangle(mBrush, rect);
        }

        /**
         * 获取底端所在的行数。底端是指方块最下方的有效格。
         * @return 底端所在的行数
         */
        public abstract int GetBottom();

        /**
         * 获取顶端所在的行数。顶端是指方块最上方的有效格。
         * @return 顶端所在的行数
         */
        public abstract int GetTop();

        /**
         * 对不能下落的处理。
         */
        protected abstract void HandleCannotMoveDown();

        /**
         * 下落。
         * @return 总是 true
         */
        public virtual bool MoveDown() {
            this.Erase();
            mRow++;
            this.Draw();

            return true;
        }

        /**
         * 左移。
         */
        public virtual void MoveLeft() {
            this.Erase();
            mLine--;
            this.Draw();
        }

        /**
         * 右移。
         */
        public virtual void MoveRight() {
            this.Erase();
            mLine++;
            this.Draw();
        }

        /**
         * 变形。
         */
        public abstract void Transform();
    }
}
